
/**
 * 创建验证规则
 *
 * @param {(string | any[] | RegExp)} reg 正则表达式
 * @param {string} message 验证失败提示
 * @return {*} 
 */
const createRule = function (reg: string | any[] | RegExp, message: string) {
    if (typeof reg === 'string') {
        return function (str: string) {
            var re = new RegExp(reg);
            return !re.test(str) ? null : message;
        }
    } else if (Array.isArray(reg)) {
        return function (str: string) {
            str = str.toLocaleLowerCase();
            for (let i = 0; i < reg.length; i++) {
                if (str.indexOf(reg[i]) >= 0) {
                    return message;
                }
            };
            return null;
        }
    } else {
        return function (str: string) {
            var re = new RegExp(reg);
            return re.test(str) ? null : message;
        }
    }
}

/**
 * 验证长度
 *
 * @param {string} type
 * @param {*} str
 * @return {*}  {(string | null | undefined)}
 */
const judgeLength = function (type: string, str: any): string | null | undefined {
    const [key, num] = type.split(':');
    let length, unit;
    if (Array.isArray(str)) {
        length = str.length;
        unit = '个';
    } else {
        length = (str + '').toString().length;
        unit = '位';
    };
    const _num = Number(num);
    switch (key) {
        case 'eq':
            return _num == length ? null : `只能为${_num}${unit}`;
        case 'neq':
            return _num != length ? null : `不能为${_num}${unit}`;
        case 'gt':
            return _num > length ? null : `需要大于${_num}${unit}`;
        case 'lt':
            return _num < length ? null : `需要小于${_num}${unit}`;
        case 'gte':
            return _num >= length ? null : `不能小于${_num}${unit}`;
        case 'lte':
            return _num <= length ? null : `不能大于${_num}${unit}`;
        default:
            console.log('error => 未找到验证规则');
            return undefined
    }
}

/**
 * 验证规则
 *
 * @type {Record<string, (str: any) => string | null>}
 */
const rules: Record<string, (str: any) => string | null> = {
    year: createRule(/^(19|20)\d{2}$/, '格式错误'),
    float: createRule(/^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$/, '只能为数字'),
    bankNum: createRule(/^\d{16}|\d{19}$/, '格式错误'),
    telephone: createRule(/^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4}?)$/, '格式错误'),
    number: createRule(/^[0-9]*$/, '只能为数字'),
    int: createRule(/^[1-9]+([0-9]*)?$/, '只能为整数'),
    phone: createRule(/^1[0-9]{10}$/, '格式错误'),
    allChinese: createRule(/^[\u4e00-\u9fa5]+$/, '只能为中文'),
    haveChinese: createRule("[\\u4e00-\\u9fa5]+", "包含中文"),
    idCard: createRule(/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$/, '格式错误'),
    url: createRule(/^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+/, '格式错误'),
    email: createRule(/^[-_A-Za-z0-9]+@([_A-Za-z0-9]+\.)+[A-Za-z0-9]{2,3}$/, '格式错误'),
    special: createRule(["~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "{", "}", "[", "]", "(", ")", ":", ";", "'", "|", "\\", "<", ">", "?", "/", "<<", ">>", "||", "//", "administrators", "administrator", "管理员", "系统管理员", "admin", "select", "delete", "update", "insert", "create", "drop", "alter", "trancate"], '不能包含特殊字符')
}


/**
 * 验证规则处理
 *
 * @param {string} type
 * @param {*} str
 * @return {*}  {(string | null | undefined)}
 */
const judgeHandler = function (type: string, str: any): string | null | undefined {
    if (type.indexOf(':') != -1) {
        return judgeLength(type, str);
    } else if (rules[type]) {
        return rules[type](str);
    } else {
        console.log('error => 未找到验证规则 ==>', type, '==>', str);
        return undefined
    }
}

/**
 * 验证
 *
 * @param {string} str 验证规则
 * @param {*} val 验证值
 * @return {*}  {(string | null)}
 */
export const judge = function (str: string, val: any): string | null {
    const ruleArr = str.split(';');
    let res = null;
    for (let i = 0; i < ruleArr.length; i++) {
        const item = ruleArr[i];
        const ans = judgeHandler(item, val);
        if (ans) {
            res = ans;
            break;
        }
    };
    return res
}
